/*  homedepot.c*/
/*	Test program for the assignment 1.*/
/*	Test the implementation of synchronization mechanisms*/
/*  of Lock and Condition.*/

/*	OceanMaster*/

/*Predefine*/
#define R_MAX 2147483647	/*R_MAX denotes the biggest possible number returned of rand(); RAND_MAX is somehow out of time.*/
#define TestCaseNum 9		/*Total number of pre defined test cases*/
#define true 1
#define false 0
#define NULL 0
typedef int bool;

/*Pre Defined Test Cases*/
/*Name*/
/*=======================Structs==========================*/
/*-------------------Customer Struct----------------------*/
/*	Struct for Customer*/
/*	To store personal data*/
/*--------------------------------------------------------*/
/*---------------------Clerk Struct-----------------------*/
/*	Struct for Clerk*/
/*	To store personal data*/
/*--------------------------------------------------------*/
/*---------------------CashReg Struct---------------------*/
/*	Struct for CashReg*/
/*	To store personal data*/
/*--------------------------------------------------------*/
/*---------------------StockBoy Struct--------------------*/
/*	Struct for Customer*/
/*	To store personal data*/
/*--------------------------------------------------------*/
/*---------------------Manager Struct---------------------*/
/*	Struct for Manager*/
/*	To store personal data*/
/*--------------------------------------------------------*/
/*========================================================*/
#define MAX_CRNum 3 
#define MAX_ClerkNum 3
#define MAX_StockBoyNum 3
#define MAX_AisleNum 5
#define MAX_CustomerNum 20
#define MAX_ItemNum 10

/*Function Define*/
int GenRandom(int limit);
void CustomerBehavior();		
void ClerkBehavior();
void ManagerBehavior();
void CashRegisterBehavior();
void StockBoyBehavior();
/*Function Define End*/

/*Constant Varible Define*/

bool ProgramRun = true;			/*Is program running?*/

int  Prices[MAX_ItemNum];					/*prices of corresponding item*/
int  ItemAmount[MAX_ItemNum];				/*Amount of each item, REMEMBER to INIT!! originally 3*/
int  ItemRestockPrediction[MAX_ItemNum];	/*Amount of each item that stockboy is restocking and will soon be restocked*/

int ClerkNum=3;					/*total # of clerks;*/
int CRNum=3;					/*total # of cash registers*/
int CustomerNum=20;				/*total # of Customer*/
int StockBoyNum=3;				/*total # of StockBoy*/
int ManagerNum = 1;				/*total # of Manager*/
int ItemNum = 10;				/*total # of Item*/
int AisleNum = 5;				/*total # of Aisle*/

/*Test Case Tricks*/
/*These Varibles is used to create specific scenario for test cases*/
int ReturnChance = 20;					/*The chance if a customer to be return customer*/
int LostChance = 25;					/*The chance a customer fails to find an item*/
int OriginItemAmount = 3;				/*Origin Amount of each Item*/
int MinBoughtEach = 1;					/*Min number of items a customer can buy*/
int MaxBoughtEach = 10;					/*Max number of items a customer can buy is [MinBoughtEach+MaxBoughtEach-1]*/
bool BornLazy[MAX_ClerkNum];			/*If a clerk will go to rest as soon as he is created?*/
int PriceFactor = 100;					/*The Factor that affects randomly generated prices*/
int MinPrice =0;						/*The Mininum price can be generated*/
bool ManagerTrackLine = true;			/*Does Manager keep track of Line himself*/
bool CustomerBusyWaiting = false;		/*This is a trick to let customer keeps searching for stockboy.This value is always false in normal simulation*/
/*Constant Verible End*/


/*Synchronization Define*/
int idLock;							/*Lock to pretect id from race condition*/
int OpLock1;							/*StartLine Exclusion*/
int OpLock2;							/*StockBoy Break Exclusion*/
int OpLock3;							/*Clerk Break Exclusion*/
int OpLock4;							/*Leaving Customer Exclusion*/
int OpLock5;							/*For StockRoom Condition Check	*/
int TableLock[MAX_CRNum];				/*Acquire this Lock before handle items on table*/
int CheckQueue;							/*Acquire this lock before check Line Lengths*/
int ScreenLock[MAX_CRNum];				/*Acquire this Lock before interact with cash register machine*/
int StockRoomLock;						/*The Lock on StockRoom*/
int ServiceButtonLock;					/*The Lock to protect service button*/
int ClerkCallLock;						/*The Lock to protect clerk call flag*/
int StockBoyStatusLock;					/*The Lock to protect Stock Boy Status*/
int AisleHelpLock[MAX_AisleNum];		/*The Lock to protect AisleHelp related monitor varibles*/
int AisleLock[MAX_AisleNum];			/*Acquire this Lock before access any item on an aisle*/
int ServiceStateLock[MAX_StockBoyNum];	/*The Lock to protect help state between a stock boy and a customer*/

int StartLine;							/*the start line*/
int ClerkOnBreak;						/*The Condition that clerks on break wait on*/
int StockBoyOnBreak;					/*The Condition that stockboys on break wait on*/
int Queue[MAX_CRNum];					/*Paying Lines*/
int Screen[MAX_CRNum];					/*The cash register machine screen State Condition*/
int Table[MAX_CRNum];					/*The Cashier Table State Condition*/
int LackMoney[MAX_CRNum];				/*If a cash register lacks money to pay return customer, he waits for Manager here*/
int StockRoomCV;						/*The Condition on which Stock Boy wait for room*/
int WaitForRestockCV[MAX_ItemNum];		/*Customers waiting for item to be restocked. It is protected by AisleLock*/
int ServiceStateCV[MAX_StockBoyNum];	/*The State Condition when a stock boy is helping a customer*/
int AisleHelpCV[MAX_AisleNum];			/*The Condition a customer waits on before a stock boy comes to serve him*/
/*Synchronization Define End*/

/*Double Varible*/
int TotalSales=0;						/*record the total sales amount.*/


/*Double Varible End*/


/*Shared Varible End*/

bool AisleNeedRestock[MAX_AisleNum];	/*record if an aisle need to be restocked*/
bool ServiceButtonOn=false;				/*If somebody pressed service button?*/
bool ClerkCall=false;					/*If somebody ask for more clerk?*/
int ClerkCallId = -1;					/*The Clerk who asked manager to wake another clerk*/

int QueueLength[MAX_CRNum];				/*Lengths of paying Lines*/

bool ClerkOnWork[MAX_ClerkNum];			/*If a Clerk is ready for customer?*/
		
int TableArea[MAX_CRNum];				/*Place to put items*/
int CashArea[MAX_CRNum];				/*Place to put money*/

int data[MAX_CRNum];					/*The data is the place to exchange information with cash register*/
int MoneyCollected[MAX_CRNum];			/*The money each cash register earned before manager empty it*/
int TotalMoneyCollected[MAX_CRNum];		/*The money each cash register ever earned*/
int MoneyLacked[MAX_CRNum];				/*The money a cash register lacks to pay a return customer*/

int StockBoyInRoom = -1;				/*Id of StockBoy currently in Stock Room*/

int StockBoyStatus[MAX_StockBoyNum];	/*Each StockBoy's status.If he is in an aisle, status is the aisle number or aisle+AisleNum; Otherwise,  -1*/
int AisleHelpLineLength[MAX_AisleNum];	/*The number of customer waiting for help on each aisle*/
int Booklet[MAX_StockBoyNum];			/*The booklet used by Customer and StockBoy to exchange information*/

int CustomerLeaving=0;					/*Total number of customers that finished shopping and left*/

bool DidSomething[MAX_StockBoyNum];
/*Shared Varible End*/

/************Nick: Please delete these functions when put in the USER PROGRAM******/
/*void Fork(void (*func)()){};*/
/*void WriteFormat(char * name, int len, int * numbers, int num_count){}*/
/*void Write(char * name, int len, int mode){printf("%s",name);}*/
/*void Yield(){}*/
/**********************************************************************************/
int modifyName(char * name, int offset, int num){
	int i=0;
	int pos=0;
	int digit;
	if(name == NULL) return -1;
	while(name[i]!='\0' && i<offset+4){
		i++;
	}
	if(name[i]=='\0' && i < offset+4) return -1;
	pos= i-1;
	while(num!=0){
		digit=num%10;
		num = (num-digit)/10;
		name[pos]=(char)(digit+48);
		pos--;
	}
	for(;pos>=offset;pos--)
		name[pos]='0';
	return 1;
}

int abs(int temp)
{
	if (temp>=0)
	{
		return temp;
	}
	return temp*(-1);
}

/*Main function for Home Depot Simulation*/
/*========================================================*/

int
main()	/*main function for Home Depot*/
{
	char* name;
	int  numbers[6];
	int i;
	Write("============================================\n", 45, 1);
	Write("         Home Depot Store Simulation        \n\n", 46 ,1);
	Write("          part2 of project1,CSCI402         \n", 45 ,1);
	Write("                  Group#11                  \n", 45 ,1);
	Write("============================================\n\n", 46 ,1);
	
	
	
	/*------------------------------*/
	/*           INITIALIZE*/
	/*------------------------------*/
	
	/*Initialization of varibles declared*/
	OpLock1 = CreateLock("OperationLock1",15); 		
	OpLock2 = CreateLock("OperationLock2",15);
	OpLock3 = CreateLock("OperationLock3",15);
	OpLock4 = CreateLock("OperationLock4",15);
	OpLock5 = CreateLock("OperationLock5",15);
	idLock=CreateLock("IDLock",7);
	StartLine = CreateCondition("StartLine",10);

	ClerkOnBreak = CreateCondition("ClerkBreak",11);
	StockBoyOnBreak = CreateCondition("StockBoyBreak",14);

	CheckQueue = CreateLock("CheckQueueLock",15);
	
	StockRoomLock = CreateLock("StockRoomLock",14);
	StockRoomCV = CreateCondition("StockRoomCV",12);

	ServiceButtonLock = CreateLock("ServiceButtonLock",18);
	StockBoyStatusLock = CreateLock("StockBoyStatusLock",19);
	
	ClerkCallLock=CreateLock("ClerkCallLock",14);
	
	/*Initialization of array varibles declared*/
	for(i=0;i<CRNum;i++)
	{
		/*char* name;*/

		name="Queue0000";
		modifyName(name,5,i);	
		Queue[i] = CreateCondition(name,9);

		QueueLength[i] = 0;									/*origin length of each line is 0*/
		ClerkOnWork[i] = true;								/*Erery clerk is assumed to be on work at beginning*/
		BornLazy[i] = false;								/*he won't go to rest directly*/

		name="TableLock0000";
		modifyName(name,9,i);
		TableLock[i]=CreateLock(name,13);
		
		name="Table0000";
		modifyName(name,5,i);
		Table[i]=CreateCondition(name,9);
		
		TableArea[i]=-1;									/*default value*/
		CashArea[i]=0.0;

		name="ScreenLock0000";
		modifyName(name,10,i);
		ScreenLock[i]=CreateLock(name,14);
		
		
		name="Screen0000";
		modifyName(name,6,i);
		Screen[i]=CreateCondition(name,10);
		
		
		data[i] = -1.0;										/*-1 is used to denote initial state for cash register*/

		MoneyCollected[i] = 0.0;							/*originally each cash register has no profit*/
		TotalMoneyCollected[i] = 0.0;

		MoneyLacked[i] = -1.0;								/*MoneyLacked < 0 means no money lacked*/
		
		name="Lack0000";
		modifyName(name,4,i);
		LackMoney[i]=CreateCondition(name,8);
		
	}

	for(i=0;i<StockBoyNum;i++)
	{

		name="ServiceStateLock0000";
		modifyName(name,16,i);
		ServiceStateLock[i]=CreateLock(name,20);
		
		name="ServiceState0000";
		modifyName(name,12,i);
		ServiceStateCV[i]=CreateCondition(name,16);

		Booklet[i] = -1;									/*Default value*/
		StockBoyStatus[i] = -1;								/*StockBoyStatus == -1 means he is out of any aisle*/
	}

	for (i=0;i<AisleNum;i++)
	{

		name="AisleHelpLock0000";

		modifyName(name,13,i);
		AisleHelpLock[i]=CreateLock(name,17);
		
		name="AisleHelpCV0000";
		modifyName(name,11,i);
		AisleHelpCV[i]=CreateCondition(name,15);
		
		name="AisleLock0000";
		modifyName(name,9,i);
		AisleLock[i]=CreateLock(name,13);
		
		AisleHelpLineLength[i]=0;							/*originally no customer is waiting for help in any aisle*/
		AisleNeedRestock[i] = false;						/*no aisle need to be restocked at very beginning*/
	}
	

	for(i=0;i<ItemNum;i++)
	{

		Prices[i]=MinPrice+1+GenRandom(PriceFactor);		/*generate price*/
		ItemAmount[i]=OriginItemAmount;						/*Default amount of each item is 3*/
		ItemRestockPrediction[i]=0;							/*Item to be restocked is 0	*/

		name="WaitForRestockCV0000";
		modifyName(name,16,i);
		WaitForRestockCV[i]=CreateCondition(name,20);
	}

	
	Write("================ Program Start =============\n",45,1);	/*Simulation Start*/
	numbers[0] = ClerkNum;
	WriteFormat("Number of Clerks = [%d]\n",25, numbers,1);				/*print as sample out put*/
	numbers[0] = StockBoyNum;
	WriteFormat("Number of StockBoys = [%d]\n",28, numbers,1);
	numbers[0] = CRNum;
	WriteFormat("Number of CashRegisters = [%d]\n",32,numbers,1);
	numbers[0] = CustomerNum;
	WriteFormat("Number of Customers = [%d]\n",28, numbers,1);
	numbers[0] = ManagerNum;
	WriteFormat("Number of Managers = [%d]\n",27,numbers,1);
	numbers[0] = AisleNum;
	WriteFormat("Number of Aisles = [%d]\n",25, numbers,1);
	Write("	Items:\n", 8, 1);
	Write("		Number - Price\n", 17, 1);
	for(i=0;i<ItemNum;i++){
		numbers[0]=i;
		numbers[1]=Prices[i]/10;
		numbers[2]=Prices[i]%10;
		WriteFormat("		[%d] - $[%d.%d]\n",19,numbers,3);
	}

	/*build Threads*/

	/*Manager*/
	for(i=0;i<ManagerNum;i++)
	{
		Fork(ManagerBehavior);
		Yield();	
	}

	/*CashRegisters*/
	for(i=0;i<CRNum;i++)
	{
		Fork(CashRegisterBehavior);		/* Fork a new thread on CashRegister's Behavior, that makes him a CR*/
		Yield();						/* EVERY TIME A NEW THREAD IS CREATED, YIELD TO IT!! To make sure they are waiting on start line;*/
	}
	
	/*StockBoys*/
	for(i=0;i<StockBoyNum;i++)
	{
		Fork(StockBoyBehavior);					/* Fork a new thread on StockBoy's Behavior, that makes him a StockBoy*/
		Yield();						/* EVERY TIME A NEW THREAD IS CREATED, YIELD TO IT!! To make sure they are waiting on start line;*/
	}

	/*Customers	*/
	for(i=0;i<CustomerNum;i++)
	{
		Fork(CustomerBehavior);							/* Fork a new thread on Customer's Behavior, that makes him a customer*/
		Yield();								/* EVERY TIME A NEW THREAD IS CREATED, YIELD TO IT!! To make sure they are waiting on start line;*/
	}

	/*Clerks*/
	for(i=0;i<ClerkNum;i++)
	{
		Fork(ClerkBehavior);					/* Fork a new thread on Clerk's Behavior, that makes him a clerk*/
		Yield();						/* EVERY TIME A NEW THREAD IS CREATED, YIELD TO IT!! To make sure they are waiting on start line;*/
	}

	Yield();

/*	for (i=0;i<300;i++)
	{
		Yield();
	}
*/	
	/*simulation start*/
/*	AcquireLock(OpLock1);
	BroadcastCondition(StartLine,OpLock1);*/								/*simulation started, let created thread to start running*/
													/*Professor Crowley says it won't affect the result*/
/*	ReleaseLock(OpLock1);*/
	Exit(0);

}

void
WaitForStart()										/*Wait here for the signal to start*/
{
	AcquireLock(OpLock1);
	WaitCondition(StartLine,OpLock1);
	ReleaseLock(OpLock1);							/*wait for signal to run*/
}

int
GetAisleByItem(int item)
{
	return (item/2);								/*The method to find aisle number by item number*/
}
/*=======================================================*/

/*-------------------Customer Minor----------------------*/
/*	Minor Behaviors of Customer*/
/*	Lots of synchronization involved*/
/*-------------------------------------------------------*/
void
PressServiceButton()								/*Press the service button*/
{
	AcquireLock(ServiceButtonLock);
	ServiceButtonOn=true;
	ReleaseLock(ServiceButtonLock);
}


int
AskStockBoyForItem(int item,int id)					/*When customer ask stock boy for position of item*/
{
	int numbers[6];
	int helpAisle = -1;
	int myStockBoy = -1;
	int myAisle = -1;
	int i,j;
	
	/*find an aisle number depending on the stockboy's Status.*/
	/*We will enter aisles one by one, and see if there is a StockBoy whose Status == aisleID; If yes, we know there is one workging in current aisle ,and wait here*/
	while(true)
	{
		for(i=0; i<AisleNum; i++)				/*Enter	aisles one by one			*/
		{
			AcquireLock(AisleHelpLock[i]);			/*Once in an aisle, acquire its aisle help lock*/
			for(j=0; j<StockBoyNum; j++)
			{
				/* between the steps a customer find a stockboy, and increase the aisleHelpLine, */
				/* the stockboy has no chance to run*/
				AcquireLock(StockBoyStatusLock);
				if( (StockBoyStatus[j] != -1) && ( StockBoyStatus[j] % AisleNum == i) )/*if there is a stock boy in current aisle, remember this aisle*/
				{
					ReleaseLock(StockBoyStatusLock);
					helpAisle = i;
					break;
				}
				ReleaseLock(StockBoyStatusLock);
			}
			if(helpAisle != -1)						/*helpAisle!=-1 means we found a stockboy, break without releasing AisleHelpLock*/
				break;
			ReleaseLock(AisleHelpLock[i]);					/*Otherwise, release lock, look another aisle*/
		}
			
		if(helpAisle == -1)							/*looked into all aisles and found no stockboy*/
		{
			if(CustomerBusyWaiting)					/*This trick is only used in scenario that without manager.*/
				continue;
			numbers[0]=id;
			WriteFormat("Customer [%d] looked in all aisle for StockBoy. He is now requesting help by pressing service button.\n",103,numbers, 1);
			PressServiceButton();					/*press service button*/
			WaitForStart();							/*wait on start line for calling from manager when stockboy is ready*/
			continue;								/*when waken uo by manager, go back to head of this function, re do task*/
		}
		else										/*We found a stock boy in aisle*/
		{
			/*printf("===Customer [%d] find a stockboy in aisle [%d], get in line\n", id, helpAisle);*/
		
			AisleHelpLineLength[helpAisle]++;		/*Change help line length*/
			WaitCondition(AisleHelpCV[helpAisle],AisleHelpLock[helpAisle]);			/*wait in help CV*/
			ReleaseLock(AisleHelpLock[helpAisle]);				/*After wake up, release help lock: help line length should have been decremented by stock boy*/

			/* find which stockboy is ready for helping me*/

			/*printf("===Customer [%d] is told one stockboy is waiting for him, he is searching status [%d] in aisle [%d]\n", id, helpAisle + AisleNum,helpAisle);*/
		
			AcquireLock(StockBoyStatusLock);
			for(i=0; i<StockBoyNum; i++)		/*look which stockboy said to serve me */
			{
				/*printf("StockBoy #%d Status: %d, I am searching for status %d\n",i,StockBoyStatus[i],helpAisle+AisleNum);*/
				if(StockBoyStatus[i] == helpAisle + AisleNum)/*A stock boy ready to serve will set his status to [ AisleNumber + AisleNum  ]*/
				{
					StockBoyStatus[i] = helpAisle;	/*Reset this stockboy's Service status, so that other customer won't ask him at the same time*/
					myStockBoy = i;
					break;
				}
			}
			ReleaseLock(StockBoyStatusLock);
			
			numbers[0]=id;
			numbers[1]=myStockBoy;
			WriteFormat("Customer [%d] is asking for assistance from StockBoy [%d]\n",59,numbers,2);
		
			/*Start interaction with stockboy*/
			AcquireLock(ServiceStateLock[myStockBoy]);
		
			Booklet[myStockBoy] = id;				/*First, tell stockboy my id*/
			
			SignalCondition(ServiceStateCV[myStockBoy],ServiceStateLock[myStockBoy]);
			WaitCondition(ServiceStateCV[myStockBoy],ServiceStateLock[myStockBoy]);	
			
			/*printf("=== %s ask a question: where is item%d\n", name, item);*/
			Booklet[myStockBoy] = item;				/*Then, tell stockboy the item I want */
			SignalCondition(ServiceStateCV[myStockBoy],ServiceStateLock[myStockBoy]);	
			WaitCondition(ServiceStateCV[myStockBoy],ServiceStateLock[myStockBoy]);		
			
			myAisle = Booklet[myStockBoy];			/*Then, get answer from stockboy*/
			SignalCondition(ServiceStateCV[myStockBoy],ServiceStateLock[myStockBoy]);	/*Tell stockboy I am satisfied*/
			
			numbers[0]=id;
			numbers[1]= myAisle;
			numbers[2]= myStockBoy;
			WriteFormat("Customer [%d] got aisle [%d] from StockBoy [%d]\n" , 49, numbers, 3);
			ReleaseLock(ServiceStateLock[myStockBoy]);
			/*Interaction with stockboy end*/

			return myAisle;
		}
	}
}

void
GetItem(int item)
{
	int aisle = GetAisleByItem(item);				/*Fetch the aisle number*/
 

	/*WriteFormat("Get item on aisle %d \n",23,&aisle,1);
	WriteFormat("aisle lock is %d \n",19,AisleLock+aisle,1);*/


	AcquireLock(AisleLock[aisle]);					/*Enter Aisle*/

	while(true)
	{
		if(ItemAmount[item]>0)						/*If Item is not empty, get it and leave*/
		{
			ItemAmount[item]--;
			break;
		}
		else										/*Else, wait for it to be restocked*/
		{
			/*Item Not Enough, have to wait*/
			WaitCondition(WaitForRestockCV[item],AisleLock[aisle]);
			continue;								/*When told item is restocked, redo GetItem();*/
		}
	}

	AisleNeedRestock[aisle]=true;					/*Since I just fetched that item, lit Aisle light saying this aisle nees restock*/
	ReleaseLock(AisleLock[aisle]);
}

void 
CallManagerForClerk()								/*If there is no clerk available, call manager*/
{
	AcquireLock(ClerkCallLock);
	ClerkCall = true;
	ReleaseLock(ClerkCallLock);
}

int
FindShortestQueueAndWait(int id)					/*find the shortest queue, and wait there*/
{
	int people=R_MAX;							/*RAND_MAX is the biggest integer defined*/
	int number = -1;
	int numbers[6];
	int i;
	while(true)
	{
		AcquireLock(CheckQueue);
	
		for(i=0;i<CRNum;i++)					/*loop all lines*/
		{
			if(!ClerkOnWork[i])						/*If that line is closed, check next*/
				continue;

			if(QueueLength[i]<people)				/*If Line length is shorter, remember his number and line length*/
			{
				people=QueueLength[i];
				number=i;
			}
		}

		if(number == -1)							/*No Line is picked, means All line is closed, shoule call manager*/
		{
			/*printf("Customer %d: can't find any clerk, call manager!!!\n",id);*/
			CallManagerForClerk();					/*Call manager*/
			ReleaseLock(CheckQueue);
			WaitForStart();							/*wait in start line, the manager will call him*/
			continue;								/*Redo Find Shortest after wakeup*/
		}

		numbers[0]=id;
		numbers[1]=number;
		numbers[2]=people;
		WriteFormat("Customer [%d] chose Clerk [%d] with line length of [%d]\n",57,numbers, 3);/*When called by clerk, start to show bought item*/

		QueueLength[number]++;						/*Add self to that line*/
		WaitCondition(Queue[number],CheckQueue);			/*Wait*/
		QueueLength[number]--;						/*When awake from wait, leave the line to stand in front of table*/
		ReleaseLock(CheckQueue);
		return number;
	}
}

void
ShowItem(int item,int queueNumber)					/*show item to clerk on queueNumber*/
{
	TableArea[queueNumber]=item;
	SignalCondition(Table[queueNumber],TableLock[queueNumber]);
	WaitCondition(Table[queueNumber],TableLock[queueNumber]);
}

int
TellClerkToCountAndPay(int queueNumber,int id, bool ret)/*Tell clerk transaction over*/
{
	int numbers[6];
	int total;
	ShowItem(-1,queueNumber);						/*According to protocol, show clerk -1 means transaction is over*/
	total = CashArea[queueNumber];			/*Get the total cost returned from clerk*/
	SignalCondition(Table[queueNumber],TableLock[queueNumber]);	/*Tell clerk I acknowladged the total cost*/
	
	numbers[0]=id;
	numbers[1]=total/10;
	numbers[2]=total%10;
	numbers[3]=queueNumber;
	/*numbers[1]=total;*/
	/*numbers[2]=queueNumber;*/
	if(ret){
		WriteFormat("Customer [%d] receives [%d.%d] from Clerk [%d] and is now waiting for receipt.\n", 83, numbers, 4);
	}
	else{
		WriteFormat("Customer [%d] pays [%d.%d] to Clerk [%d] and is now waiting for receipt.\n", 77, numbers, 4);
	}
	WaitCondition(Table[queueNumber],TableLock[queueNumber]);	/*wait for clerk to do something*/
	
	return total;
}

void
Leave(int queueNumber)									/*Cuatomer leave the store*/
{
	SignalCondition(Table[queueNumber],TableLock[queueNumber]);	/*Tell clerk I left*/
	AcquireLock(OpLock4);						/*Add leaving customer statistics. Manager will rely on this to close sstore*/
	CustomerLeaving++;
	/*printf("Total Finished Customer : %d\n", CustomerLeaving);*/
	ReleaseLock(OpLock4);
}

/*---------------------Customer Major--------------------*/
/*Customer Behavior*/
/*	the main Logic of a Customer*/
/*-------------------------------------------------------*/
int nextCustomerId=0;
void
CustomerBehavior()
{
	/*need to have a lock!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
	int id;
	int numbers[6];
	int MAX_TotalNum = 100;
	int Items[MAX_TotalNum];
	int QueueNumber;
	int i;
	bool retCustomer;
	int tmp;
	int TotalNum;
	AcquireLock(idLock);
	id=nextCustomerId++;
	ReleaseLock(idLock);

	
	/*NEEDN'T WORRY LOCAL VARIBLES, THEY ARE STORED IN STACK, AND WON'T BE MANIPULATED BE OTHER THREADS*/
	retCustomer = false;							/*Am I a return customer?*/

	tmp = GenRandom(100);							/*Roll the dice to decide if I am a return customer*/
	if(tmp<ReturnChance)
		retCustomer = true;

	TotalNum = MinBoughtEach+GenRandom(MaxBoughtEach);/*Randomly generate total Number of items to buy. Assuming buy no more than MaxBoughtEach*/
	numbers[0]=id;
	numbers[1]=TotalNum;
	if(retCustomer)										/*Start purchasing*/
		WriteFormat("Customer [%d] needs to return [%d] no.of item.\n", 48, numbers, 2);
	else
		WriteFormat("Customer [%d] wants to buy [%d] no.of items.\n",46, numbers, 2);	

	/*Items = (int*)malloc(TotalNum*sizeof(int));*/
	/*int * Items = new int[TotalNum];*/					/*Generate Item List */
	for(i=0;i<TotalNum;i++)				
	{
		Items[i]=GenRandom(ItemNum);					/*Randomly generate item id*/
		
		if(retCustomer)									/*Return customer don't need to fetch items.*/
			continue;

		tmp = GenRandom(100);							/*Roll the dice to decide if customer fail to find the item*/
		if(tmp<LostChance)								/*If failed, customer have to look for a stockboy for help*/
		{
			numbers[0]=id;
			numbers[1]=Items[i];
			WriteFormat("Customer [%d] is not able to find item [%d] and is searching for StockBoy.\n",76, numbers,2);
			AskStockBoyForItem(Items[i],id);			/*Ask StockBoy for help*/
		}

		GetItem(Items[i]);								/*Take the item;	*/
		/*printf("Customer %s: Bought item %d\n",name,Items[i]);*/
	}
	
	WriteFormat("Customer %d: Finished purchasing, trying to find a paying queue\n",65,&id,1);
	/*printf("Customer %s: Finished purchasing, trying to find a paying queue\n",name);//finish purchasing,trying to find a queue*/
	
	QueueNumber = FindShortestQueueAndWait(id);		/*find the shortest queue, and wait there*/
	AcquireLock(TableLock[QueueNumber]);			/*Make Critical Section*/
	
	ShowItem(id,QueueNumber);							/*Tell Clerk my name*/

	if(retCustomer)
		ShowItem(1,QueueNumber);
	
	else
		ShowItem(0,QueueNumber);
	
	/*ShowItem((retCustomer?1:0),QueueNumber);*/			/*Tell Clerk my purpose: 1,return item; 0,buy item;*/

	for(i=0;i<TotalNum;i++)							/*show items to clerk, one by one*/
	{
		numbers[0]=id;
		numbers[1]=Items[i];
		numbers[2]=QueueNumber;
		WriteFormat("Customer [%d] gives item [%d] to Clerk [%d].\n",46, numbers,3);
		ShowItem(Items[i],QueueNumber);			
	}
		numbers[0]=id;
		numbers[1]=QueueNumber;
		numbers[2]=TotalNum;
	WriteFormat("Customer [%d] tells Clerk [%d], I have given you all my [%d] items.\n",69 ,numbers,3);

	TellClerkToCountAndPay(QueueNumber, id, retCustomer);/*tell clerk to count total, and pay for them,then wait for receipt*/

	Leave(QueueNumber);									/*take recipet and leave store*/
		
	numbers[0]=id;
	numbers[1]=QueueNumber;
	WriteFormat("Customer [%d] got receipt from Clerk [%d] and is now leaving.\n", 63, numbers, 2);
	
	ReleaseLock(TableLock[QueueNumber]);			/*Critical Section End*/
	Exit(0);
}

/*---------------------Clerk Minor-----------------------*/
/*	Minor Behaviors of Clerk*/
/*	Lots of synchronization involved*/
/*-------------------------------------------------------*/

int
CheckWaitingQueue(int id)								/*Check length of paying line*/
{
	int length = QueueLength[id];
	return length;
}

void
CallManager(int id)										/*Clerk will cal manager if there are too many customer in line*/
{
	WriteFormat("Clerk [%d] sees more than 4 people in line and calls manager.\n", 63, &id, 1);
	AcquireLock(ClerkCallLock);
	ClerkCall=true;
	ClerkCallId = id;
	ReleaseLock(ClerkCallLock);
}

void
ClerkRest(int id)										/*Clerk go to rest, assumes ClerkOnWork has been marked false*/
{
	int i;
	int numbers[2];
	numbers[0]=id;
	numbers[1]=id;
	WriteFormat("Clerk [%d] is leaving Cash Register [%d] and going on break.\n",62, numbers,2);
	AcquireLock(OpLock3);
	WaitCondition(ClerkOnBreak,OpLock3);						/*Wait on clerk break condition*/
	ReleaseLock(OpLock3);
	
	WriteFormat("Clerk [%d] was called by Manager to work.\n", 43, numbers, 1);	/*Waken by manager to work*/
	AcquireLock(CheckQueue);
	ClerkOnWork[id]=true;								/*Reset ClerkOnWork to true*/
	ReleaseLock(CheckQueue);

	for(i=0;i<20;i++)								/*Wait for some time, let customer wait in line*/
		Yield();
}

void
GreetOneWaiter(int id)									/*Tell one customer in line to hand off items*/
{
	SignalCondition(Queue[id],CheckQueue);
}

int 
checkTable(int id)										/*Check what has been put in table by customer*/
{
	SignalCondition(Table[id],TableLock[id]);
	WaitCondition(Table[id],TableLock[id]);
	return TableArea[id];
}

void
TypeInCashier(int id,int item)							/*Clerk type information in cash register*/
{
	data[id] = (int) item;
	SignalCondition(Screen[id],ScreenLock[id]);
	WaitCondition(Screen[id],ScreenLock[id]);					/*Wait for cash register's reflection*/
}

int
ReadScreen(int id)										/*Type in all item scanned, and read screen for total cost*/
{
	int total;
	TypeInCashier(id,-1);								/*According to protocol, -1 tells cash register transcation over and let it count total*/
	total = data[id];							/*Read total*/
	return total;
}

void
ProvideReceipt(int id)
{
	SignalCondition(Table[id],TableLock[id]);
	WaitCondition(Table[id],TableLock[id]);
}


/*---------------------Clerk Major-----------------------*/
/*Clerk Behavior*/
/*	the main Logic of a Clerk*/
/*-------------------------------------------------------*/

/*Assumption:	Each Clerk works on CashRegister corresponding to his number*/
int nextClerkId=0;
void
ClerkBehavior()
{
	int id;
	int i;
	int numbers[6];
	AcquireLock(idLock);
	id=nextClerkId++;
	ReleaseLock(idLock);
	
	if(BornLazy[id])									/*Used by test case, some clerk go to rest at very beginning*/
	{	
		AcquireLock(CheckQueue);
		ClerkOnWork[id]=false;
		ReleaseLock(CheckQueue);
		ClerkRest(id);
	}

	for(i=0;i<5;i++)								/*When just created, yield some time to make sure some customer finish shopping*/
		Yield();

	/*printf("Clerk %s: Ready to work\n",name);*/

	while(ProgramRun)									/*As long as program is running*/
	{
		int people;
		int cusId;
		bool retCustomer;
		int item;
		int total;

		WriteFormat("Clerk [%d] Running...\n",23,&id,1);

		for(i=0;i<5;i++)
		{
			Yield();
		}
		
		AcquireLock(CheckQueue);
		people = CheckWaitingQueue(id);				/*Check line length*/
		
		/*printf("Clerk %s: %2d people are waiting in line\n",name,people);*/
		
		if(people>=4)									/*If more than 4 people waiting in line, call manager*/
			CallManager(id);
		else if(people==0)								/*If no people waiting, go to rest*/
		{
			WriteFormat("Clerk [%d] Sleepy...\n",22,&id,1);
			if(!ProgramRun)								/*If Program stops, Exit*/
				Exit(0);
			ClerkOnWork[id]=false;						/*Mark work status to be false*/
			ReleaseLock(CheckQueue);
			ClerkRest(id);								/*go to rest*/
			continue;									/*when waken by manager, start a new work cycle*/
		}
		
		/*printf("Clerk %s: Tell one customer in line to take off items\n",name);*/
		
		GreetOneWaiter(id);								/*Tell one customer to show item, and grabing Table Lock*/
		AcquireLock(TableLock[id]);
		ReleaseLock(CheckQueue);

		WaitCondition(Table[id],TableLock[id]);			/*wait for customer to come*/
		
		cusId = TableArea[id];							/*check customer id placed on table area by customerk*/

		AcquireLock(ScreenLock[id]);

		TypeInCashier(id,cusId);						/*Type customer id in cash register*/

		retCustomer = checkTable(id);					/*check if the customer is a return customer*/
	
		/*printf("!!!!! Clerk [%d] knows Customer [%d] is [%s] a return customer!!!!\n",id, cusId, retCustomer?"":"NOT");*/
		
		TypeInCashier(id,retCustomer);					/*Type customer purpose in cash register*/

		item = checkTable(id);							/*start to scan customer item*/

		while(item!=-1)									/*As long as item!= -1, keep taking new items and type in cash register*/
		{
			numbers[0]=id;
			numbers[1]=item;
			numbers[2]=cusId;
			WriteFormat("Clerk [%d] got item [%d] from Customer [%d]\n", 45, numbers, 3);
			
			numbers[2]=id;
			WriteFormat("Clerk [%d] gave item [%d] to Cash Register [%d] for scanning.\n", 63, numbers, 3);
			
			TypeInCashier(id,item);						/*type item into cashier*/
			item = checkTable(id);						/*check another item	*/
		}
		
		/*printf("Clerk %s: Command computer to count total\n",name);*/
		
		total = ReadScreen(id);					/*Tell machine to count and read Cashier Screen for total*/
		
		numbers[0]=id;
		numbers[1]=total/10;
		numbers[2]=total%10;
		numbers[3]=id;
		WriteFormat("Clerk [%d] got total cost $[%d.%d] from Cash Register [%d]\n",63,numbers,4);
		
		numbers[1]=cusId;
		numbers[2]=total/10;
		numbers[3]=total%10;
		WriteFormat("Clerk [%d] tells Customer [%d] total cost is $[%d.%d].\n",59,numbers,4);	/*Tell Customer amount*/
	
		if(retCustomer)									/*If this is a return customer, we have to provide cash along with total value*/
		{
			SignalCondition(Screen[id],ScreenLock[id]);		/*tell cash register to prepare cash*/
			WaitCondition(Screen[id],ScreenLock[id]);		/*wait for cash to be prepared together with receipt*/
			CashArea[id] = total;						/*put money on cash area*/
			
			numbers[0]=id;
			numbers[1]=total/10;
			numbers[2]=total%10;
			numbers[3]=id;
			WriteFormat("Clerk [%d] got money $[%d.%d] from Cash Register [%d].\n", 59, numbers, 4);
			SignalCondition(Table[id],TableLock[id]);			/*tell customer to pick cash*/
			
			numbers[3]=cusId;
			WriteFormat("Clerk [%d] gave the money $[%d.%d] to Customer [%d].\n", 57, numbers,4);
			WaitCondition(Table[id],TableLock[id]);				/*Now customer has been paid*/
		}
		else											/*if it is a normal customer, collect cash from him */
		{
			CashArea[id] = total;						/*show total cost to customer*/
			SignalCondition(Table[id],TableLock[id]);			/*Tell customer to pay*/
			WaitCondition(Table[id],TableLock[id]);				/*Now customer has paid*/
			
			numbers[0]=id;
			numbers[1]=total/10;
			numbers[2]=total%10;
			numbers[3]=cusId;
			WriteFormat("Clerk [%d] got money $[%d.%d] from Customer [%d].\n",54, numbers, 4);
			SignalCondition(Screen[id],ScreenLock[id]);		/*tell chase register money has been collected*/
			
			numbers[3]=id;
			WriteFormat("Clerk [%d] gave the money $[%d.%d] to Cash Register [%d].\n", 62, numbers,4);
			WaitCondition(Screen[id],ScreenLock[id]);		/*wait for machine to take in money*/
		}
		SignalCondition(Screen[id],ScreenLock[id]);			/*tell cash register to print receipt*/
		WaitCondition(Screen[id],ScreenLock[id]);			/*wait for receipt*/
		
		numbers[0]=id;
		numbers[1]=id;
		WriteFormat("Clerk [%d] got receipt from Cash Register [%d].\n",49, numbers,2);
		ReleaseLock(ScreenLock[id]);
		
		numbers[1]=cusId;
		WriteFormat("Clerk [%d] gave the receipt to Customer [%d] and tells him to leave.\n", 70, numbers, 2);
		ProvideReceipt(id);								/*provide receipt to customer, and wait for him to leave*/
		ReleaseLock(TableLock[id]);
	}
	Exit(0);
}

/*---------------------CashReg Minor---------------------*/
/*	Minor Behaviors of CashRegister*/
/*	Lots of synchronization involved*/
/*  by OceanMaster*/
/*-------------------------------------------------------*/

int
CheckInput(int id)										/*check input from clerk*/
{
	int i;
	SignalCondition(Screen[id],ScreenLock[id]);
	WaitCondition(Screen[id],ScreenLock[id]);
	i = (int)data[id];
	return i;
}

void
DisplayTotal(int id, int total)						/*Display total cost to clerk*/
{
	data[id]=total;
	SignalCondition(Screen[id],ScreenLock[id]);
	WaitCondition(Screen[id],ScreenLock[id]);
}

/*---------------------CashReg Major---------------------*/
/*CashRegister Behavior*/
/*	the main Logic of a CashRegister*/
/*  by OceanMaster*/
/*-------------------------------------------------------*/
int nextCRId=0;
void 
CashRegisterBehavior()
{
	int id;
	int numbers[6];
	AcquireLock(idLock);
	id=nextCRId++;
	ReleaseLock(idLock);
	
	AcquireLock(ScreenLock[id]);							/*The Lock controls interaction with cash register*/
	
	/*printf("CashMachine %s: Trun On\n",name);*/

	while(ProgramRun)									/*As long as programming is running..*/
	{
		/*printf("CashMachine %s: Ready for input\n",name);*/
	
		int total = 0.0;								/*Assuming a new transcation starts*/
		int cusId = CheckInput(id);						/*Get customer id*/
		bool retCustomer = CheckInput(id);				/*Get customer purpose : return customer or not*/

		int item = CheckInput(id);						/*Scan a new item*/
		int amount = 0;									/*Store total amount*/

		WriteFormat("CashRegister [%d] Running...\n",30,&id,1);
			
		while(item!=-1)									/*If it isn't -1; (Item is -1 means all item is scanned, should display Total amount)*/
		{
			amount++;									/*count total amount of items*/
			total += Prices[item];						/*Add item's price to total cost*/
			numbers[0]=id;
			numbers[1]=item;
			numbers[2]=id;
			WriteFormat("Cash Register [%d] got item [%d] from clerk [%d] to scan.\n", 59, numbers,3);
			item = CheckInput(id);						/*Scan a new item*/
		}
		
		numbers[0]=id;
		numbers[1]=amount;
		numbers[2]=id;
		WriteFormat("Cash Register [%d] has scanned all [%d] items for Customer [%d]\n", 65, numbers, 3);
		numbers[0]=id;
		numbers[1]=total/10;
		numbers[2]=total%10;
		numbers[3]=cusId;
		numbers[4]=id;
		numbers[5]=amount;
		WriteFormat("Cash Register [%d] gave total cost $[%d.%d] for Customer [%d] to Clerk[%d] for [%d] items.\n", 95, numbers, 6);
		
		DisplayTotal(id,total);							/*Display total Amount to screen*/
		
		if(retCustomer)									/*We have to prepare cash for return customer*/
		{
			if((MoneyCollected[id]-total)>=0)			/*If MoneyCollected enough to pay customer*/
			{
				MoneyCollected[id]-=total;				/*Pay it directly*/
			}
			else										/*Otherwise, we have to count on manager to solve the problem*/
			{
				int lacked = total - MoneyCollected[id];	/*Count how much I lack*/
				MoneyCollected[id] = 0;						/*Empty Money Collected to pay customer*/
				
				numbers[0]=id;
				numbers[1]=lacked/10;
				numbers[2]=lacked%10;
				WriteFormat("Cash Register [%d] informed the Manager that he needs $[%d.%d].\n",68,numbers,3);
				MoneyLacked[id] = lacked;					/*store amount of money lacked*/
				WaitCondition(LackMoney[id],ScreenLock[id]);			/*Wait for manager to come*/
				
				
				WriteFormat("Cash Register [%d] received $[%d.%d] from the Manager.\n",59, numbers,3);
			}
		
			data[id]=total;								/*display total*/
			
			numbers[0]=id;
			numbers[1]=id;
			WriteFormat("Cash Register [%d] gave the money to Clerk [%d].\n",50,numbers, 2);
			
			SignalCondition(Screen[id],ScreenLock[id]);		/*provided cash*/
			WaitCondition(Screen[id],ScreenLock[id]);		/*wait for clerk to transmit money*/
		}
		else											/*If it is normal customer, now cash should have been put in front of machine*/
		{
			MoneyCollected[id]+=total;					/*take cash in machine balance*/
			
			numbers[0]=id;
			numbers[1]=id;
			WriteFormat("Cash Register [%d] got the money from Clerk [%d].\n", 51, numbers, 2);
			
			SignalCondition(Screen[id],ScreenLock[id]);		/*tell clerk money has been saved*/
			WaitCondition(Screen[id],ScreenLock[id]);		/*wait for command to provide receipt*/
		}
		numbers[0]=id;
		numbers[1]=id;
		numbers[2]=cusId;
		WriteFormat("Cash Register [%d] gave receipt to Clerk[%d] for Customer [%d].\n", 65, numbers, 3);
		SignalCondition(Screen[id],ScreenLock[id]);			/*provided receipt*/
		
		numbers[1]=MoneyCollected[id]/10;
		numbers[2]=MoneyCollected[id]%10;
		WriteFormat("Cash Register [%d] total sale is $[%d.%d].\n",47, numbers, 3);
	}
	ReleaseLock(ScreenLock[id]);
	Exit(0);
}


/*---------------------StockBoy Minor--------------------*/
/*	Minor Behaviors of StockBoy*/
/*	Lots of synchronization involved*/
/*	by Kuai Yu*/
/*-------------------------------------------------------*/
void
RetrieveStockItem(int item, int id)						/*Retrieve item form stock room*/
{
	int numbers[6];
	int i;
	/*printf("===StockBoy [%d] want to retrieve item [%d]\n",id,item);*/
	AcquireLock(OpLock5);				
	while(true)
	{
		if(StockBoyInRoom!=-1)							/*If stockroom is currently occupied*/
		{
			numbers[0]=id;
			numbers[1]=StockBoyInRoom;
			WriteFormat("StockBoy [%d] is waiting for StockBoy [%d] to leave the stock room.\n",69,numbers,2);
			WaitCondition(StockRoomCV,OpLock5);				/*wait for stock boy in room to leave*/
			continue;									/*Re do check stock room*/
		}
		StockBoyInRoom = id;							/*If not occupied, register self*/
		ReleaseLock(OpLock5);
		break;
	}
	AcquireLock(StockRoomLock);							/*Enter stock room*/
	
	numbers[0]=id;
	WriteFormat("StockBoy [%d] is in stock room.\n",33, numbers, 1);

	for(i=0;i<10;i++)								/*It takes time to pick item*/
		Yield();

	numbers[1]=item;
	WriteFormat("StockBoy [%d] retrieve one new item [%d] from stock room.\n", 59 , numbers,2 );
	
	WriteFormat("StockBoy [%d] leaves stock room.\n", 34, numbers,1);
	ReleaseLock(StockRoomLock);						/*leave stock room*/
	AcquireLock(OpLock5);
	/*OpLock5->Acquire();*/
	StockBoyInRoom = -1;								/*mark nobody is in stockroom*/
	SignalCondition(StockRoomCV,OpLock5);						/*tell one stockboy to retry entering stockroom*/
	ReleaseLock(OpLock5);
}

void 
ServeCustomerAndLeaveAisle(int StockBoyId, int MyAisle)	/*Stock boy serve suctomer and leave aisle after that*/
{
	int numbers[6];
	int i;
	/*printf("===StockBoy [%d] want to serve customer in aisle [%d]\n",StockBoyId,MyAisle);*/
	
	if(MyAisle<0)										/*if stockboy is not in any aisle, won't serve customer*/
		return;

	/*char * name = currentThread->getName();*/

	/*printf("=== %s is yielding...\n", name);*/

	for (i=0;i<5;i++)								/*it takes some time to walk to the end of aisle*/
	{
		Yield();
	}
	AcquireLock(AisleHelpLock[MyAisle]);					/*Acquire help lock*/

	while(AisleHelpLineLength[MyAisle]>0)				/*while there is still customer waiting for service*/
	{
		int cusId;
		int item;
		int aisle;
		DidSomething[StockBoyId] = true;				/*I did something when help customer*/

		/*printf("===StockBoy [%d] find [%d] customers waiting in aisle %d\n", StockBoyId, AisleHelpLineLength[MyAisle],MyAisle);*/

		SignalCondition(AisleHelpCV[MyAisle],AisleHelpLock[MyAisle]);	/*Tell one customer to ask question*/

		AisleHelpLineLength[MyAisle]--;					/*decrement helpline length*/
		
		AcquireLock(StockBoyStatusLock);				/*Acquire status lock before release helplock, make sure customer has no chance to run before i am ready*/
	
		ReleaseLock(AisleHelpLock[MyAisle]);

		/*printf("===StockBoy [%d] is waiting to help one customer in aisle %d\n", StockBoyId, MyAisle);*/
	
		StockBoyStatus[StockBoyId] = MyAisle + AisleNum;/*mark my status as [Aisle +AisleNum], that is the status for ready to serve in aisle;*/

		/*printf("===StockBoy [%d] set his Status: %d\n", StockBoyId, StockBoyStatus[StockBoyId]);*/
		
		AcquireLock(ServiceStateLock[StockBoyId]);		/*Acquire service state lock, entering service section*/

		ReleaseLock(StockBoyStatusLock);
		
		WaitCondition(ServiceStateCV[StockBoyId],ServiceStateLock[StockBoyId]);	/* wait for customer to ask question*/
		
		cusId=Booklet[StockBoyId];					/*get customer id*/

		SignalCondition(ServiceStateCV[StockBoyId],ServiceStateLock[StockBoyId]);/* tell customer to go on*/
		
		WaitCondition(ServiceStateCV[StockBoyId],ServiceStateLock[StockBoyId]);
		
		numbers[0]=StockBoyId;
		numbers[1]=cusId;
		WriteFormat("StockBoy [%d] is approached by Customer [%d] for assistance.\n",62, numbers,2);

		item=Booklet[StockBoyId];					/*get customer's question*/

		/*printf("=== %s get a question from customer: where is item%d\n", name, item);*/
		
		aisle = GetAisleByItem(item);				/*find the answer*/

		Booklet[StockBoyId]=aisle;						/*put answer on booklet*/
		
		numbers[0]=StockBoyId;
		numbers[1]=aisle;
		numbers[2]=cusId;
		numbers[3]=item;
		WriteFormat("StockBoy [%d] gave aisle [%d] to Customer [%d] for item [%d].\n",63,numbers,4);
		
		SignalCondition(ServiceStateCV[StockBoyId],ServiceStateLock[StockBoyId]);	/*tell customer to read answer*/

		WaitCondition(ServiceStateCV[StockBoyId],ServiceStateLock[StockBoyId]);		/*wait for customer's thanks*/

		ReleaseLock(ServiceStateLock[StockBoyId]);
		AcquireLock(AisleHelpLock[MyAisle]);
	}
	AcquireLock(StockBoyStatusLock);							/*Mark self as out of aisle*/
	/*printf("=== %s leaves aisle%d\n", name, MyAisle);*/
	StockBoyStatus[StockBoyId]=-1;								

	ReleaseLock(StockBoyStatusLock);
	
	/*printf("===StockBoy [%d] left aisle [%d]\n",StockBoyId,MyAisle);*/

	ReleaseLock(AisleHelpLock[MyAisle]);

}

int
ScanAisle(int id)												/*Stock boy scans aisles to see if items is lacked*/
{
	int i,j,k;
	for (i=0;i<AisleNum;i++)								/*loop all aisles*/
	{
		AcquireLock(AisleLock[i]);								/*Entering aisle*/
		AcquireLock(StockBoyStatusLock);
		
		/*printf("=== %s is scanning aisle%d\n", currentThread -> getName(), i );*/
		StockBoyStatus[id]=i;									/*Update stock boy status. let customer see him*/
		
		ReleaseLock(StockBoyStatusLock);
		
		for(j = 0; j<2; j++)								/*check items on this aisle*/
		{
			int index;
			for(k=0;k<2;k++)								/*it takes time to check item status*/
				Yield();
		
			 index = i*2+j;									/*calculate item id*/
			if ( (ItemAmount[index] + ItemRestockPrediction[index] )<OriginItemAmount)/*If Item is lacked, and still have space to restock*/
			{
				ItemRestockPrediction[index]++;					/*Mark item that I will restock one of this item*/
				ReleaseLock(AisleLock[i]);
				ServeCustomerAndLeaveAisle(id,i);				/*Serve customer and leave aisle*/
				return index;									/*Return item id that i am going to restock*/
			}
		}
		ReleaseLock(AisleLock[i]);
		ServeCustomerAndLeaveAisle(id,i);						/*Serve customer before leave aisle*/
	}

	return -1;													/*If no item need to restock, return -1*/
}

/*Assumption: */
/*current thread is holding AisleLock[aisle]*/
bool
isItemFull(int item)											/*Check if item is full*/
{
	return ((ItemAmount[item]+ItemRestockPrediction[item]) == OriginItemAmount);
}

bool
isAisleFull(int aisle)											/*Check if aisle is full*/
{
	return ( isItemFull(aisle*2) && isItemFull(aisle*2+1) );
}

bool
PutStockItem(int item, int id)									/*Put retrieved item on its aisle*/
{
	int numbers[6];
	bool more = false;						

	int aisle = GetAisleByItem(item);							/*calculate aisle number*/

	AcquireLock(StockBoyStatusLock);
	StockBoyStatus[id] = aisle;									/*Mark self status in that aisle*/
	ReleaseLock(StockBoyStatusLock);

	AcquireLock(AisleLock[aisle]);								/*Enter aisle*/
	
	ItemAmount[item]++;											/*Restock item */
	ItemRestockPrediction[item]--;								/*Delete the mark I left before go get the item*/
	SignalCondition(WaitForRestockCV[item],AisleLock[aisle]);			/*wake up one customer waiting for item*/
	
	numbers[0]=id;
	WriteFormat("StockBoy [%d] is checking if more items are to be re-stocked.\n",63,numbers,1);
	
	if(isAisleFull(aisle))
		AisleNeedRestock[aisle] = false;						/*If aisle is full, unset the mark that this aisle need restock*/
	else if(!isItemFull(item))									/*If this item is still lacked, go get another*/
	{
		/*Mark I will tock it again*/
		numbers[1]=item;
		WriteFormat("StockBoy [%d] goes back to stock room for item [%d].\n",54,numbers,2);
		ItemRestockPrediction[item]++;							/*Leave a mark I am already trying to restock one item of this type*/
		more = true;											/*I will get more this item*/
	}
	
	ReleaseLock(AisleLock[aisle]);								/*Leave Aisle*/

	ServeCustomerAndLeaveAisle(id,aisle);						/*Serve customer and leave aisle*/
	
	return more;
}

void
StockBoyRest(int id)											/*Stock boy go to rest*/
{
	WriteFormat("StockBoy [%d] is going on break.\n",34,&id,1);
	AcquireLock(OpLock2);
	WaitCondition(StockBoyOnBreak,OpLock2);
	WriteFormat("StockBoy [%d] got call from Manager.\n",38,&id,1);
	ReleaseLock(OpLock2);
}
/*---------------------StockBoy Major--------------------*/
/*StockBoy Behavior*/
/*	the main Logic of a StockBoy*/
/*	by Kuai Yu*/
/*-------------------------------------------------------*/
int nextStockBoyId = 0;  /* Kuai Yu!!!!!!!!!*/

void
StockBoyBehavior()
{
	int id;
	AcquireLock(idLock);
	id=nextStockBoyId++;
	ReleaseLock(idLock);

	while(ProgramRun)											/*As long as program is running*/
	{
		int item;
	
		WriteFormat("StockBoy [%d] Running...\n",26,&id,1);
	
		DidSomething[id] = false;
		
		item = ScanAisle(id);								/*Scan aisles for lacked item*/
		
		if(item != -1)											/*if one item is lacked*/
		{
			/*printf("=== %s found item %d is lacked, go to retrieve item\n", name, item);		*/
			int aisle;
			DidSomething[id] = true;							/*mark self did something in his loop*/
			aisle = GetAisleByItem(item);
		
			RetrieveStockItem(item,id);							/*retrieve one item of this type*/
			/*printf("=== %s is in aisle%d, ready to restock item %d\n", name, aisle, item);*/
			
			while(PutStockItem(item, id))						/*put item on aisle. As long as it is still lacked, get one another and restock*/
			{
				RetrieveStockItem(item,id);
			}
		}

		if(!DidSomething[id])									/*If I did nothing in this loop, go to rest*/
		{
			WriteFormat("StockBoy [%d] Sleepy\n",22,&id,1);
			if(!ProgramRun)										/*If program end, exit*/
				Exit(0);
			/*printf("StockBoy === %s go to have a rest\n", name);*/
			StockBoyRest(id);
		}
	}	
	Exit(0);
}

/*---------------------Manager Minor----------------------*/
/*	Minor Behaviors of Manager*/
/*	Lots of synchronization involved*/
/*	by Momo*/
/*--------------------------------------------------------*/
void
ManagerIdle()													/*Manager do this between tasks*/
{
	int i;
	for(i=0;i<10;i++)
		Yield();
}

void 
WakeUpCustomer()												/*wake up customers*/
{
	AcquireLock(OpLock1);
	
	BroadcastCondition(StartLine,OpLock1);
	
	
	ReleaseLock(OpLock1);

}

void 
CollectCash()													/*Manager collect cash from register machines*/
{
	int numbers[3];
	int i,j;
	for (i=0;i<CRNum;i++)
	{
		int lacked;
		for(j=0;j<2;j++)									/*It takes some time to collect cash from machine*/
			Yield();
		AcquireLock(ScreenLock[i]);								/*Acquire cash register's lock*/
		
		lacked = MoneyLacked[i];							/*Read register information*/
		if(lacked>0)											/*if this register is needing money*/
		{
			MoneyCollected[i]=0-lacked;	/*TotalSales -= lacked;	//provide money to this cash reg*/
			MoneyLacked[i]=-1;									/*reset data*/
			
			SignalCondition(LackMoney[i],ScreenLock[i]);				/*tell that cash register I have provided money*/
			numbers[0]=lacked/10;
			numbers[1]=lacked%10;
			numbers[2]=i;
			WriteFormat("Manager gave $[%d.%d] to cash register [%d].\n",49,numbers,3);
		}
		TotalSales+=MoneyCollected[i];							/*Collect money, add to total sales			*/
		TotalMoneyCollected[i]+=MoneyCollected[i];				/*Count total sales of eace cash register*/
		
		numbers[0]=i;
		WriteFormat("Cash Register [%d] drawer is emptied by Manager.\n",50,numbers,1);
		
		numbers[1]= MoneyCollected[i]/10;
		numbers[2]= abs(MoneyCollected[i]%10);
		WriteFormat("Cash Register [%d] total sale until now is $[%d.%d].\n",57, numbers,3);	/*Professor crowley says it is OK*/
		
		WriteFormat("Manager emptied Cash Register [%d] drawer.\n",44,numbers,1);
		
		numbers[0]=TotalSales/10;
		numbers[1]=abs(TotalSales%10);
		WriteFormat("Manager has total sale of $[%d.%d].\n", 40,numbers,2);
		MoneyCollected[i]=0;									/*Empty cash reg balance*/
		ReleaseLock(ScreenLock[i]);								/*Release lock*/
	}

	if(GenRandom(100)<50)										/*Randomly print out this statement*/
	{
		numbers[0]=TotalSales/10;
		numbers[1]=abs(TotalSales%10);
		WriteFormat("-------Total Sale of the entire store until now is $[%d.%d]-------\n",71, numbers,2);
	}
}
/*---------------------Manager Major----------------------*/
/*Manager Behavior*/
/*	the main Logic of the Manager*/
/*by Momo*/
/*--------------------------------------------------------*/
int nextManagerId=0;
void
ManagerBehavior()
{
	int id;
	int numbers[6];
	int i,j,k;
	AcquireLock(idLock);	
	id=nextManagerId++;
	ReleaseLock(idLock);

	while(true)
	{	
		WriteFormat("Manager Running...\n",20,0,0);

		ManagerIdle();

		AcquireLock(ClerkCallLock);								/*check if there is a call for clerk*/
		if (ClerkCall)
		{
			if(ClerkCallId!=-1)									/*if clerk call id is -1, it is from customer, otherwise, print clerk id*/
			{
				numbers[0]=ClerkCallId;
				WriteFormat("Manager got a call from Clerk [%d].\n",37,numbers,1);
				ClerkCallId = -1;
			}
			
			AcquireLock(OpLock3);
			
			SignalCondition(ClerkOnBreak,OpLock3);						/*wake up one clerk*/
			Write("Manager wakes up Clerk.\n",24,1);
			
			ReleaseLock(OpLock3);
			WakeUpCustomer();									/*wake up customers that may be waiting*/
			ClerkCall=false;
			ClerkCallId = -1;
		}
		
		
		ReleaseLock(ClerkCallLock);
		
		ManagerIdle();

		for (j=0;j<AisleNum;j++)							/*Check if there is an aisle need restock*/
		{
			
			AcquireLock(AisleLock[j]);
			if (AisleNeedRestock[j])							/*If there is*/
			{
				AcquireLock(OpLock2);
				
				BroadcastCondition(StockBoyOnBreak,OpLock2);			/*wake up all stockboys*/
				/*printf("Items missed in Aisle %d!!Manager call all the Stockboy to work!!\n",j);*/
				ReleaseLock(OpLock2);
				ReleaseLock(AisleLock[j]);
				break;
			}

			ReleaseLock(AisleLock[j]);
		}

		ManagerIdle();

		AcquireLock(ServiceButtonLock);						/*check if service button is pressed*/
		if (ServiceButtonOn)									/*if pressed*/
		{
			/*wake up all stock boys that are taking break;*/
			AcquireLock(OpLock2);
			
			BroadcastCondition(StockBoyOnBreak,OpLock2);				/*wake up all stockboys*/
			Write("Manager wakes up StockBoy.\n",27,1);
			
			ReleaseLock(OpLock2);
			WakeUpCustomer();									/*wake up customers that may be waiting*/
			ServiceButtonOn = false;
		}
		
		ReleaseLock(ServiceButtonLock);

		ManagerIdle();

		CollectCash();											/*collect cash from each cash register*/

		ManagerIdle();
		
		if(ManagerTrackLine)									/*Manager keep track of line lengths himself*/
		{
			AcquireLock(CheckQueue);
			for(k=0;k<CRNum;k++)
				if(QueueLength[k]>0 && (!ClerkOnWork[k]))		/*If there is a line on which people is waiting but no clerk work*/
					break;
			ReleaseLock(CheckQueue);

			if(k!=CRNum)										/*such a line exist*/
			{													/*wake up a clerk*/
				AcquireLock(OpLock3);
				
				SignalCondition(ClerkOnBreak,OpLock3);
				Write("Manager wakes up Clerk.\n",24,1);
				
				ReleaseLock(OpLock3);
				WakeUpCustomer();								/*wake up customer that may be waiting*/
				ClerkCall=false;
			}
		}

	AcquireLock(OpLock4);										/*Check if all customers have left*/

		if (CustomerLeaving!=CustomerNum)
		{
			ReleaseLock(OpLock4);
			continue;											/*if not ,continue*/
		}

		ReleaseLock(OpLock4);

		
		/*Exiting Codes!										//Else, close store!*/

		ProgramRun=false;
		/*printf("All customer leaves, program exit!!i\n");*/
		
		CollectCash();											/*Collect cash for last time*/

		/*printf("Total Sales: %0.1f\n",TotalSales);*/
		for (i=0;i<CRNum;i++)									/*Print Statictics*/
		{
			numbers[0]=i;
			numbers[1]=TotalMoneyCollected[i]/10;
			numbers[2]=abs(TotalMoneyCollected[i]%10);
			WriteFormat("Total Sale from Cash Register [%d] is $[%d.%d].\n",49,numbers,3);
		}
		
		numbers[0]=TotalSales/10;
		numbers[1]=abs(TotalSales%10);
		WriteFormat("Total Sale of the entire store is $[%d.%d].\n", 45, numbers,2);

		break;													/*Thread end*/
	}
	Exit(0);
}


/*=======================================================*/

/*Description:*/
/*Generate a random integer that  0=< and < limit*/
/*Assumption:*/
/*Already randomized;*/
int GenRandom(int limit)
{
	/*int num;*/
	/*int num2;*/
	/*num = rand()*1.0;*/
	/*printf("%f\n",num);*/
	/*num = limit*num;*/
	/*printf("%f\n",num);*/
	/*num2 = (int)R_MAX+1.0;*/
	/*printf("%f / %f = %f\n",num,num2,num/num2);*/
	/*num = num /num2;*/
	/*num = num +1;*/
	/*printf("%d\n",(int)num);*/
	return Random(limit);
}
